﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace SpeedTest
{
	public partial class PanelCase : UserControl
	{

		private bool dataChanged = false;
		private bool testerChanged = false;
		private bool environChanged = false;
		private Data data = null;
		private string itemID = String.Empty;
		private DataTable caseTable = null;
		private DataTable testerAsgnTable = null;
		private DataTable environAsgnTable = null;

		private EditMode mode = EditMode.EditMode;
		private string planID = String.Empty;
		private string parentPath = String.Empty;

		public PanelCase(Data data, EditMode mode, string planID, string parentPath)
		{
			InitializeComponent();
			this.mode = mode;
			this.data = data;
			this.planID = planID;
			this.parentPath = parentPath;
			LoadTesterData();
			LoadEnvironData();
			LoadStepData();
            cmboPriority.SelectedIndex = 2; //set default priority to 2.
			EnableInput(true);
		}

		public PanelCase(Data data, string itemID, bool enableInput)
		{
			InitializeComponent();
			this.data = data;
			this.itemID = itemID;
			LoadData();
			EnableInput(false);
		}

        public delegate void OnSave(string id, NodeType nodeType);
		public event OnSave Save;
		public delegate void OnCancel();
		public event OnCancel Cancel;

		public string ItemID
		{
			get
			{
				return itemID;
			}
			set
			{
				itemID = value;
			}
		}
		
		public bool Changed
		{
			get
			{
				return dataChanged;
			}
		}

		private bool LoadData()
		{
			if (data != null)
			{
				caseTable = data.GetCaseSuiteByID(itemID, NodeType.CaseNode);	
			}

			if (caseTable != null && caseTable.Rows.Count > 0)
			{
				txtTitle.Text = caseTable.Rows[0]["Description"].ToString();
				txtCategory.Text = caseTable.Rows[0]["Category"].ToString();
				cmboPriority.SelectedIndex = Int32.Parse(caseTable.Rows[0]["Priority"].ToString());
			}

			LoadTesterData();
			LoadEnvironData();
			LoadStepData();
			LoadTesterAssignmentData();
			testerChanged = false;	//reset to avoid changes when programmatically checking
			LoadEnvironAssignmentData();
			environChanged = false;
			return true;
		}

		private void LoadTesterData()
		{
			DataTable testerTable = null;

			if (data != null) { testerTable = data.GetUserNames(); }

			if (testerTable != null && testerTable.Rows.Count > 0)
			{
				lstTester.ValueMember = "Value";
				lstTester.DisplayMember = "Text";
				lstTester.Items.Clear();

				int selIndex = -1;
				//add them and set the active index to the selected.
				for (int i = 0; i < testerTable.Rows.Count; i++)
				{
					ComboItem ci = new ComboItem();
					ci.Text = testerTable.Rows[i]["Name"].ToString();
					ci.Value = testerTable.Rows[i]["ID"].ToString();

					int index = lstTester.Items.Add(ci);
				}

				if (selIndex >= 0)
				{
					lstTester.SelectedIndex = selIndex;
				}
			}
		}

		private void LoadEnvironData()
		{
			DataTable environTable = null;
			if (data != null) { environTable = data.GetEnvironments(); }

			if (environTable != null && environTable.Rows.Count > 0)
			{

				lstEnvironment.DisplayMember = "Text";
				lstEnvironment.ValueMember = "Value";
				lstEnvironment.Items.Clear();
				//add them and set the active index to the selected.
				for (int i = 0; i < environTable.Rows.Count; i++)
				{
					ComboItem ci = new ComboItem();
					ci.Text = environTable.Rows[i]["Description"].ToString();
					ci.Value = environTable.Rows[i]["ID"].ToString();

					int index = lstEnvironment.Items.Add(ci);
				}
			}
		}

		private void LoadTesterAssignmentData()
		{
			if (data != null) { testerAsgnTable = data.GetTesterAssignmentsByCaseID(itemID); }

			if (testerAsgnTable != null && testerAsgnTable.Rows.Count > 0)
			{
				foreach (DataRow row in testerAsgnTable.Rows)
				{
					int index = FindCheckedListItem(lstTester, row["TesterID"].ToString());
					if (index != -1)
					{
						lstTester.SetItemChecked(index, true);
					}
				}
			}
		}

		private void LoadEnvironAssignmentData()
		{
			if (data != null) { environAsgnTable = data.GetEnvironAssignmentsByCaseID(itemID); }

			if (environAsgnTable != null && environAsgnTable.Rows.Count > 0)
			{
				foreach (DataRow row in environAsgnTable.Rows)
				{
					int index = FindCheckedListItem(lstEnvironment, row["EnvironmentID"].ToString());
					if (index != -1)
					{
						lstEnvironment.SetItemChecked(index, true);
					}
				}
			}
		}

		private int FindCheckedListItem(CheckedListBox checkedList, string itemID)
		{
			if (checkedList != null && !String.IsNullOrEmpty(itemID))
			{
				for (int i = 0; i < checkedList.Items.Count; i++)
				{
					ComboItem ci = (ComboItem)checkedList.Items[i];
					if (ci.Value.Equals(itemID)) { return i; }
				}
			}

			return -1;
		}

		private void LoadStepData()
		{
			DataTable stepsTable = null;
			if (caseTable == null || String.IsNullOrEmpty(caseTable.Rows[0]["Steps"].ToString()))
			{//give it an empty one
				stepsTable = new DataTable("Steps");
				stepsTable.Columns.Add("Step");
				stepsTable.Columns.Add("ExpectedResult");
			}
			else 
			{
				stepsTable = GetTableFromXML(caseTable.Rows[0]["Steps"].ToString());
				stepsTable.TableName = "Steps";
			}

			gridSteps.AutoGenerateColumns = false;
			DataGridViewColumn stepColumn = gridSteps.Columns["Step"];
			DataGridViewColumn resultColumn = gridSteps.Columns["ExpectedResult"];

			stepColumn.DataPropertyName = "Step";
			resultColumn.DataPropertyName = "ExpectedResult";

			gridSteps.DataSource = stepsTable;
		}

		private void btnAttachments_Click(object sender, EventArgs e)
		{
			AttachmentsForm attachForm = new AttachmentsForm(data, itemID);
			DialogResult res = attachForm.ShowDialog();
		}

		private DataTable GetTableFromXML(string xmlData)
		{
			DataSet set = new DataSet();
			StringReader reader = new StringReader(xmlData);
			set.ReadXml(reader);
			DataTable table = set.Tables[0].Copy();
			return table;
		}

		private string GetXMLFromTable(DataTable table)
		{
			if (table.Rows.Count > 0)
			{
				string outXml = String.Empty;
				DataSet set = new DataSet();
				set.Tables.Add(table);
				StringBuilder builder = new StringBuilder(outXml);
				StringWriter writer = new StringWriter(builder);
				set.WriteXml(writer);
				set.Tables.Remove(table);
				return builder.ToString();
			}
			else
			{
				return String.Empty;
			}
		}

		private void UpdateTesterAssignments()
		{
			//Delete all first
			if (data.DeleteTesterAssignmentByCaseID(itemID))
			{
				//Add back in the current assignment
				for (int i = 0; i < lstTester.CheckedItems.Count; i++)
				{
					ComboItem ci = (ComboItem)lstTester.CheckedItems[i];

					DataTable table = new DataTable();
					table.Columns.Add("CaseID");
					table.Columns.Add("TesterID");

					string[] row = new string[2];
					row[0] = itemID;
					row[1] = ci.Value;

					table.Rows.Add(row);

					data.InsertTesterAssignment(table);
				}
			}
			else
			{
				MessageBox.Show("An error occurred while trying to update the assigned testers");
			}
		}

		private void UpdateEnvironmentAssignments()
		{
			//Delete all first
			if (data.DeleteEnvironAssignmentByCaseID(itemID))
			{
				//Add back in the current assignment
				for (int i = 0; i < lstEnvironment.CheckedItems.Count; i++)
				{
					ComboItem ci = (ComboItem)lstEnvironment.CheckedItems[i];

					DataTable table = new DataTable();
					table.Columns.Add("CaseID");
					table.Columns.Add("EnvironmentID");

					string[] row = new string[2];
					row[0] = itemID;
					row[1] = ci.Value;

					table.Rows.Add(row);

					data.InsertEnvironAssignment(table);
				}

			}
			else
			{
				MessageBox.Show("An error occurred while trying to update the assigned environment");
			}
		}

		private void btnSave_Click(object sender, EventArgs e)
		{
            if (!ValidateInput()) { return; }

			if (mode == EditMode.EditMode)
			{
				caseTable.Rows[0]["Description"] = txtTitle.Text;
				caseTable.Rows[0]["Category"] = txtCategory.Text;
				caseTable.Rows[0]["LastModifiedByID"] = data.User.UserID;	//TODO: set current user
				caseTable.Rows[0]["DateModified"] = DateTime.Now;

				if (cmboPriority.SelectedIndex != -1)
				{
					caseTable.Rows[0]["Priority"] = cmboPriority.SelectedIndex;
				}

				string outXml = GetXMLFromTable((DataTable)gridSteps.DataSource);
				caseTable.Rows[0]["Steps"] = outXml;

				data.UpdateCaseSuiteByID(caseTable, itemID);
				//TODO: Environment assignments - need to get environ table and update assignments.
			}
			else
			{
				//[ParentPlanID], [NodeType], [Path], [Description], [CreatorID], [Category], [AssignedTesterID], [Steps]
				caseTable = new DataTable();
				caseTable.Columns.Add("ParentPlanID");
				caseTable.Columns.Add("NodeType");
				caseTable.Columns.Add("Path");
				caseTable.Columns.Add("Description");
				caseTable.Columns.Add("CreatorID");
				caseTable.Columns.Add("Category");
				caseTable.Columns.Add("Priority");
				caseTable.Columns.Add("Steps");

				string[] record = new string[8];
				record[0] = planID;
				record[1] = "2"; //NodeType.CaseNode
				record[2] = data.GetCaseSuitePath(planID, parentPath);
				record[3] = txtTitle.Text;
				record[4] = data.User.UserID;
				record[5] = txtCategory.Text;
				record[6] = cmboPriority.SelectedIndex.ToString();
				string outXml = GetXMLFromTable((DataTable)gridSteps.DataSource);
				record[7] = outXml;
				
				caseTable.Rows.Add(record);

				itemID = data.InsertCase(caseTable).ToString();
			}

			//separate table changes - performed for both modes
			if (testerChanged) { UpdateTesterAssignments(); }
			if (environChanged) { UpdateEnvironmentAssignments(); }

			EnableInput(false);

			Save.Invoke(itemID, NodeType.CaseNode);
		}

        private bool ValidateInput()
        {
            string requiredFields = String.Empty;

            if (String.IsNullOrEmpty(txtTitle.Text)) { requiredFields += "Title\n"; }

            if (!String.IsNullOrEmpty(requiredFields))
            {
                MessageBox.Show("The following required fields are empty\n" + requiredFields, "Error");
                return false;
            }

            return true;
        }

		private void EnableInput(bool enable)
		{
			txtCategory.Enabled = enable;
			txtTitle.Enabled = enable;
			lstTester.Enabled = enable;
			lstEnvironment.Enabled = enable;
			cmboPriority.Enabled = enable;
			gridSteps.Enabled = enable;

			btnAttachments.Enabled = enable;
			if (IsPermitted(btnEdit, data.User.Plans)) { btnEdit.Enabled = !enable; }
			else { btnEdit.Enabled = false; }
			btnSave.Enabled = enable;
			btnCancel.Enabled = enable;

			gridSteps.ClearSelection();
		}

		private bool IsPermitted(Button btn, Permissions perm)
		{
			if (btn == btnEdit) { return perm.Edit; }

			return false;
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			if (mode == EditMode.EditMode)
			{
				LoadData();
				EnableInput(false);
			}
			else
			{
				Cancel.Invoke();
			}
		}

		private void btnEdit_Click(object sender, EventArgs e)
		{
			EnableInput(true);
		}

		private void mnuSelectAll_Click(object sender, EventArgs e)
		{
			for (int i = 0; i < lstEnvironment.Items.Count; i++)
			{
				lstEnvironment.SetItemChecked(i, true);
			}
		}

		private void lstEnvironment_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			//determines whether an update needs to occur
			environChanged = true;
		}

		private void lstTester_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			//determines whether an update needs to occur
			testerChanged = true;
		}
	}
}
